package com.onecar.carplatform.jtt.codec;

import com.onecar.carplatform.common.protocol.basics.JtMessage;
import com.onecar.carplatform.common.utils.BcdUtil;
import com.onecar.carplatform.jtt.utils.JttUtils;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufAllocator;
import io.netty.buffer.ByteBufUtil;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToByteEncoder;
import io.netty.util.ReferenceCountUtil;
import lombok.extern.slf4j.Slf4j;

/**
 * @Author : ljq
 * @Description : jtt 协议编码器
 * @Date : 2021/8/24 19:20
 * @Version : 1.0
 */
@Slf4j
public class JttMsgEncoder extends MessageToByteEncoder<JtMessage> {
    @Override
    protected void encode(ChannelHandlerContext channelHandlerContext, JtMessage jtMessage, ByteBuf byteBuf) throws Exception {
        byte[] bodyBuf = jtMessage.encodeMsgBody();

        ByteBuf buffer = ByteBufAllocator.DEFAULT.heapBuffer(bodyBuf.length + 21); // 2019 版协议头最大是21字节
        buffer.writeShort(jtMessage.getHeader().getMsgId());
        int subContract = jtMessage.getHeader().getSubcontract() ? 1 : 0;
        int attr = (bodyBuf.length & 0x3ff) | ((jtMessage.getHeader().getEncryption() & 0b111) << 10) |
                ((subContract & 0b1) << 13) | ((jtMessage.getHeader().getVersion() & 0b111) << 14);
        buffer.writeShort(attr);
        if (jtMessage.getHeader().getVersion() > 0) {
            buffer.writeByte(jtMessage.getHeader().getVersion());
            buffer.writeBytes(BcdUtil.string2Bcd(jtMessage.getHeader().getTerminalPhone(), 10, (byte) 0));
        } else {
            buffer.writeBytes(BcdUtil.string2Bcd(jtMessage.getHeader().getTerminalPhone(), 6, (byte) 0));
        }
        buffer.writeShort(jtMessage.getHeader().getMsgSerialNumber());
        if (jtMessage.getHeader().getSubcontract()) {
            buffer.writeShort(jtMessage.getHeader().getTotalPacket());
            buffer.writeShort(jtMessage.getHeader().getPacketSequenceNum());
        }
        buffer.writeBytes(bodyBuf);
        buffer.writeByte(JttUtils.calculateXorCheckCode(buffer));
        log.debug("========> jtt encode msg header and body before escape hex:{}", ByteBufUtil.hexDump(buffer));

        byteBuf.writeByte(0x7e);
        escape(buffer, byteBuf);
        byteBuf.writeByte(0x7e);

        ReferenceCountUtil.safeRelease(buffer);
    }

    private void escape(ByteBuf row, ByteBuf writeTo) {
        int len = row.readableBytes();
        while (len > 0) {
            len--;
            byte aByte = row.readByte();
            if (aByte == 0x7e) {
                writeTo.writeByte(0x7d);
                writeTo.writeByte(0x02);
            } else if (aByte == 0x7d) {
                writeTo.writeByte(0x7d);
                writeTo.writeByte(0x01);
            } else {
                writeTo.writeByte(aByte);
            }
        }
    }
}
